Decompiling
An experimental decompiler for ARM ASM is implemented in ARM-console, module deco. Theory: Static_analysis Notations * arg0, arg1, arg2, arg3 => function arguments passed in r0, r1, r2, r3 * sp0 => stack pointer at the beginning of the function ** *(sp0), *(sp0+4), *(sp0+8) => arg4, arg5, arg6 ** *(sp0-4), *(sp0-8)... => local variables * !end => end of code path * EQ(x), NE(x): check some condition flags; e.g. EQ(x) is true if x 0 * EQ5(x) is true if x 5 (these will appear when decompiling jump tables) Forward (normal) decompilation You decompile from the start of a function. dec AJ_guess_get_DIGIC_time return struct_0xc0242000.off_0x14 /*0xC0242014*/ !end dec PrintRemconParam *(-4 + sp0) = lr0 *(-8 + sp0) = unk_R4 TH_con_puts('\nRemDriver RemconParam\n', arg1, arg2, arg3) => ret_TH_con_puts_FF066D6C TH_con_puts(' PulseWidthMin : %4ld\n', remocon_struct.PulseWidthMin /*off_0x10, 0x2AA0*/, arg2, arg3) => ret_TH_con_puts_FF066D7C TH_con_puts(' PulseWidthMax : %4ld\n', remocon_struct.PulseWidthMax /*off_0x14, 0x2AA4*/, arg2, arg3) => ret_TH_con_puts_FF066D88 ... return 0 !end dec RemOff_secret_mode_RemOn *(-4 + sp0) = lr0 *(-8 + sp0) = unk_R4 RemOff() => ret_RemOff_FF07BF08 if arg0 != 0: if arg0 1: secret_mode(0x4, 0x14, 0x1, 0x2) => ret_secret_mode_FF07BF30 if arg0 0: secret_mode(0x4, 0x14, 0x1, 0x1) => ret_secret_mode_FF07BF30 RemOn() => ret_RemOn_FF07BF38 !end Loops The decompiler doesn't supoort loops, but it will usually handle the first iteration: dec gui_main_task *(-4 + sp0) = lr0 *(-8 + sp0) = unk_R5 *(-12 + sp0) = unk_R4 memcpy(-44 + sp0, GMT_FUNCTABLE, 0x20) => ret_memcpy_FF01FFA8 gui_init_end() => ret_gui_init_end_FF01FFAC msg_queue_receive(gui_main_struct.msg_queue /*off_0x38, 0x1C3C*/, -48 + sp0, 0x0, arg3) => ret_msg_queue_receive_FF01FFC4 gui_main_struct.counter /*off_0x4, 0x1C08*/ = -1 + gui_main_struct.counter /*off_0x4, 0x1C08*/ ... Reverse decompilation This is useful when normal decompilation fails (usually when you have to deal with huge monsters like IDLEHandler or AJ_CopyDataToStorage). S PROP_SHUT String references to ff2014d4 'PROP_SHUTTER_COUNTER %d%d': AJ_CopyDataToStorage+22892: ff201390: e28f2f4f add r2, pc, #316 ; *'PROP_SHUTTER_COUNTER %d%d' 'PROP_SHUTTER_COUNTER %d%d' ... g ff201390 f201390: e28f2f4f add r2, pc, #316 ; *'PROP_SHUTTER_COUNTER %d%d' ff201394: e58d3000 str r3, sp ff201398: e5943004 ldr r3, #4 ff20139c: e3a01003 mov r1, #3 ff2013a0: e3a00083 mov r0, #131 ; 0x83 ff2013a4: ebf99810 bl @DebugMsg ... bd ff2013a4 ... DebugMsg(132, 2, msg='copyDataToStorage eventID(%#x)Data(%d)size(%d)', *(arg0), arg0->off_0x8, arg3, unk_R4, unk_R5, ...) if arg0 != 0: if *(arg0) <= 0x8005002D: if *(arg0) > 0x80030013: if *(arg0) <= 0x80040006: if *(arg0) <= PROP_HDMI_CHANGE: if *(arg0) <= 0x80030029: REGWRITE(PC, 4279483944 + 4**(arg0)) if EQ21(2147287020 + *(arg0)): *(-40 + sp0) = arg0->off_0x8 DebugMsg(131, 3, msg='PROP_SHUTTER_COUNTER %d%d', arg0->off_0x4, arg0->off_0x8, arg3, unk_R4, unk_R5, ...) !!! Stack not restored !!! !end hex(21 - 2147287020) '80030029' #define PROP_SHUTTER_COUNTER 0x80030029 :) Advanced use cp = range(0xff31695c, 0xff316970+1, 4) cp 4281428320L, 4281428324L, 4281428328L, 4281428332L, 4281428336L emusym.print_cp(cp) CODE PATH: ff31695c: e5940008 ldr r0, #8 ff316960: e3500007 cmp r0, #7 ff316964: 83a020d3 movhi r2, #211 ; 0xd3 ff316968: 828f1f55 addhi r1, pc, #340 ; *'GUI\\ShootInfo\\DlgShootOlcAFFrame.c' ff31696c: 828f0f5d addhi r0, pc, #372 ; 0xff316ae8: pointer to 0x30 ff316970: 8bf3f3a9 blhi @assert_0 cp = emusym.add_branch_info(cp) print deco.decompile(cp0, cp) SEQ(IF(-7 + MEM(8 + unk_R4), IFB(HI, SEQ(CALL(4281428336, 4278269980, 4281428712, 4281428676, 211, arg3, arg4, arg5, arg6, arg7), !end)))) print emusym.P.doprint(deco.decompile(cp0, cp)) if unk_R4->off_0x8 > 7: assert_0(0xff316ae8: pointer to 0x30, 'GUI\\ShootInfo\\DlgShootOlcAFFrame.c', 0xd3) => ret_assert_0_FF316970 !end